package com.t3.fx
{
	import com.t3.client.T3Client;
	import com.t3.events.DragEvent;
	import com.t3.tuio.TUIOCursor;
	import com.t3.tuio.TUIOEvent;
	import com.t3.util.HitTest;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.filters.BlurFilter;
	import flash.geom.Rectangle;
	import flash.net.registerClassAlias;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.utils.IDataInput;
	import flash.utils.IDataOutput;
	import flash.utils.IExternalizable;
	
	import gs.TweenMax;

	/**
	 * Letterklasse, een versleepbaar object wat een letter of een woord vast kan houden
	 * Voorstel: andere naam geven om duidelijk te maken dat het in feite een versleepbaar textfield is? 
	 * Er zijn drie verschillende soorten letters:
	 *  - woordletters
	 *  - "letter"letters
	 *  - clones
	 * 
	 * woordletters zijn de woorden in het woordenboek
	 * letter letters zijn de letters van het letterblokje
	 * en clones zijn de gekloonde letters, en die missen de kloonfunctionaliteit
	 * 
	 * Er lijken een boel omslachtige dingen in deze code te zitten, maar deze zijn om fouten te voorkomen. 
	 */
	
	public class Letter extends DraggableObject implements IExternalizable
	{
		protected var tf:TextField = new TextField();
		protected var _letter:String;	
		private static var _link:Array = [com.t3.fx.Letter];

		private var g_gridSpacing:int = 50;
		private var _fontSize:uint = 48;
		private var tempX:uint; 
		private var tempY:uint;
		private var _type:String;
		
		private var area:CharArea;
		private var words:WoordArea;
		
		public function Letter( letter:String = "", type:String = "", fontSize:uint = 48, isClone:Boolean = false ):void
		{
			this._fontSize = fontSize;
			this._letter = letter;
			this._type = type; 
			
			this.tf.text = letter;
			this.tf.setTextFormat( new TextFormat( "Lucida Sans", fontSize, 0x222222, true ) );
			this.tf.filters = [new BlurFilter(0,0,0)];
			
			this.tf.width = this.tf.textWidth+5;
			this.tf.height = this.tf.textHeight+5;
			registerClassAlias("com.t3.fx.Letter", Letter);
			super( new Rectangle( 0,0, tf.textWidth, tf.textHeight ), 0xFFFFFF, 0, (_type == "clone") );
			
			this.addChild( tf );
			
			
		}
		
		public function get letter():String
		{
			return _letter;
		}
		
		/**
		 *  Een letter kan geset worden als een woord is gesleept vanuit het woordenboek, deze zal zich dan updaten naar een nieuw woord
		 */
		public function set letter( chars:String ) : void
		{
			this._letter = chars;
			this.tf.text = chars;
			this.tf.setTextFormat( new TextFormat( "Lucida Sans", _fontSize, 0x222222, true ) );
			this.tf.filters = [new BlurFilter(0,0,0)];
			
			this.tf.width = this.tf.textWidth+5;
			this.tf.height = this.tf.textHeight+5;
		}
		
		/**
		 * Als de letter een clone is dan mist deze de eventlisteners, daarom worden deze hier toegevoegd, bovendien wordt er gekeken hoeveel
		 * letters/woorden op een bepaald moment gesleept worden, dit omdat anders de update vanuit de chararea aangeroepen wordt, deze wordt nu
		 * tegengehouden als er dus geslepen wordt. Omdat er meer dan 1 letter tegelijk geslepen wordt, is dit een variabele. Zie ook chararea
		 * Deze functie zit nu ook in woordenboek, alleen nog niet geimplementeerd.
		 */
		public override function startDragging( cursor:TUIOCursor ):DraggableObject
		{	
			if( _type == "clone" )
			{
				this.addEventListener( DragEvent.OBJECT_DROPPED, T3Client.waslijn.currentStory.notebook.objectDropped );
				this.addEventListener( DragEvent.OBJECT_REMOVED, T3Client.waslijn.currentStory.notebook.objectRemoved );
			} 
			else
			{
						
				area = T3Client.objects[ CharArea.ID ];
				words = T3Client.objects[ WoordArea.ID ]; 
				
				if ( area != null )
				{
					area.addChar( );
				}
				
				if ( words != null )
				{
					words.addChar( );
				}
			}
			
			this.addEventListener( DragEvent.OBJECT_MOVED, T3Client.waslijn.currentStory.notebook.objectMoved );
			super.startDragging( cursor );
			
			this.tf.alpha = 0.7;
			
			return this;
		}
		
		/**
		 * Kloont een letter, krijgt de lokatie van de huidige letter en geeft de letter terug ( zodat deze toegevoegd kan worden aan de lijst van letters )
		 */
		public override function clone():DraggableObject
		{
			var letter:Letter = new Letter( _letter, "clone", this._fontSize );
			letter.stageLoc = this.stageLoc;
						
			return letter;
		}
		
		/* 
		 *  Als een letter gestopt is met slepen wordt er gekeken of deze van het letterblokje af is, als dat zo is dan wordt deze neergezet, anders wordt er niets mee gedaan
		 *  Tevens wordt er, als er een woord geslepen wordt, het woord verandert als deze gestopt is met slepen. Ook dus als deze fout geslepen is ( TODO ) 
		 */
		public override function stopDragging( event:TUIOEvent ):void
		{
			area = T3Client.objects[ CharArea.ID ];
			words = T3Client.objects[ WoordArea.ID ]; 
			this.removeEventListener( DragEvent.OBJECT_MOVED, T3Client.waslijn.currentStory.notebook.objectMoved );
			
			if ( _type != "clone" )
			{
				if ( 	area == null && words == null || 
						area != null && !HitTest.complexHitTestObject( area.background, this.hitObject )   ||
						words != null && !this.hitObject.hitTestObject( words.woordenboek ) ) 
				{
					var letter:Letter = this.clone() as Letter;
			
					letter.addEventListener( DragEvent.OBJECT_DROPPED, T3Client.waslijn.currentStory.notebook.objectDropped );
					letter.addEventListener( DragEvent.OBJECT_REMOVED, T3Client.waslijn.currentStory.notebook.objectRemoved );
					letter.dragState.dropArea = this.dragState.dropArea; 
					letter.stopDragging( event );
				}
				
				area = T3Client.objects[ CharArea.ID ];
				words = T3Client.objects[ WoordArea.ID ];
				trace( _type );
				
				if (area != null && _type == "letter")
				{
					area.removeChar( );
				}
				
				if ( words != null && _type == "word")
				{
					words.changeWord( this );
					words.removeChar( );
				}
				
				this.toOrigin( false );
				this.alpha = 1;
				this.tf.alpha = 0;
				this.addEventListener( Event.ENTER_FRAME, fadeIn ) 
			}
			else
			{
			
				this.alpha = 1;
				this.tf.alpha = 1;
				
				dispatchEvent( new DragEvent( DragEvent.OBJECT_DROPPED, dragState.dropArea ) );
					
				if( dragState.dropArea == null )
				{
					gs.TweenMax.to( this, 2, { alpha:0, scaleX:0, scaleY:0, onComplete:fadeOut } );
				}
			}
			
			if( contains( dragState ) )
			{
				removeChild( dragState );
			}
		}
		
		/**
		 * Creert het fade effectje als een letter gesleept is en hij zichzelf heeft gekloond. 
		 */
		private function fadeIn( event:Event ) : void 
		{
			if ( this.tf.alpha < 1 )
			{
				this.tf.alpha += 0.01; 
			}
			else
			{
				this.removeEventListener( Event.ENTER_FRAME, fadeIn );
			}
		}
		
		private function fadeOut():void
		{
			dispatchEvent( new DragEvent( DragEvent.OBJECT_REMOVED, dragState.dropArea ) );
		}
		
		public override function get hitObject():DisplayObject
		{
			return tf;
		}
		
		public function get savedX():uint
		{
			return tempX;
		}
		
		public function get savedY():uint
		{
			return tempY;
		}		
			
		override public function writeExternal(output:IDataOutput):void 
		{
			output.writeObject(this._letter );
			output.writeObject(this.tf);
			output.writeFloat(this.stageX);
			output.writeFloat(this.stageY);
		}

		override public function readExternal(input:IDataInput):void
		{
			this._letter = input.readObject();
			this.tf = input.readObject() as TextField;
			tempX = input.readFloat();
			tempY = input.readFloat();			
		}
		
		public static function prepare():void
		{
			var letter:Letter = new Letter("x", "bogus");
			letter = null;
		} 
	}
}